﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Media.Media3D;

namespace ProjetoKinect.Model3d
{
    public class MyPoint3D 
    {
        private Double x;
	    private Double y;
	    private Double z;

        public MyPoint3D(Double x, Double y, Double z)
        {
            x = Math.Round(x, 2);
            y = Math.Round(y, 2);
            z = Math.Round(z, 2);
            
		    this.setX(x);
		    this.setY(y);
		    this.setZ(z);
	    }
        public void setAll(Double x, Double y, Double z) {
            x = Math.Round(x, 2);
            y = Math.Round(y, 2);
            z = Math.Round(z, 2);

            this.setX(x);
            this.setY(y);
            this.setZ(z);
        }
        public MyPoint3D(Point3D point3D) {
            x = Math.Round(point3D.X, 2);
            y = Math.Round(point3D.Y, 2);
            z = Math.Round(point3D.Z, 2);

            this.setX(x);
            this.setY(y);
            this.setZ(z);
        
        }

        public MyPoint3D(Vector3D vector3D)
        {
            x = Math.Round(vector3D.X, 2);
            y = Math.Round(vector3D.Y, 2);
            z = Math.Round(vector3D.Z, 2);

            this.setX(x);
            this.setY(y);
            this.setZ(z);

        }
        public MyPoint3D clone()
        {
            return new MyPoint3D(x, y, z);
        }
        public Point3D toPoint3D()
        {
            return new Point3D(x, y, z);
        }
        public Vector3D toVector3D()
        {
            return new Vector3D(x, y, z);
        }
        
        public static MyPoint3D fromVector3D(Vector3D vector3D) {
            return new MyPoint3D(vector3D.X, vector3D.Y, vector3D.Z);
        }
        
        public static Vector3D myPoint3DToVector3D(MyPoint3D mypoint3D)
        {
            return new Vector3D(mypoint3D.getX(), mypoint3D.getY(), mypoint3D.getZ());
        }
        
        public static MyPoint3D vector3DToMypoint3D(Vector3D vector3D)
        {
            return new MyPoint3D(vector3D.X, vector3D.Y, vector3D.Z);
        }

        public static Vector3D point3DToVector3D(Point3D point3D)
        {
            return new Vector3D(point3D.X, point3D.Y, point3D.Z);
        }

        public void rotateClockWiseZ(Double angle)
        {
            angle = normalizeAngle(angle);
            double x = rotateXClockWiseZ(angle);
            double y = rotateYClockWiseZ(angle);
            setX(x);
            setY(y);
        }
        public void rotateClockWiseX(Double angle)
        {
            angle = normalizeAngle(angle);

            double z = rotateZClockWiseX(angle);
            double y = rotateYClockWiseX(angle);
            setZ(z);
            setY(y);
        }
        public void rotateClockWiseY(Double angle)
        {
            angle = normalizeAngle(angle);

            double z = rotateZClockWiseY(angle);
            double x = rotateXClockWiseY(angle);
            setZ(z);
            setX(x);
        }

        public void rotateAntiClockWiseX(Double angle)
        {
            angle = normalizeAngle(angle);

            double z = rotateZClockWiseX(-angle);
            double y = rotateYClockWiseX(-angle);
            setZ(z);
            setY(y);
        }

        private double rotateXClockWiseZ(Double angle)
        {

            double first = x * Util.toCos(angle);
            double second = y * Util.toSin(angle);
            return first + second;
        }

        private double rotateYClockWiseZ( Double angle)
        {
            double first = -x * Util.toSin(angle);
            double second = y * Util.toCos(angle);
            return first + second;
        }
     
        private double rotateZClockWiseX(Double angle)
        {
            double first = -y * Util.toSin(angle);
            double second = z * Util.toCos(angle);
            return first + second;
        }

        private double rotateYClockWiseX(Double angle)
        {
            double first = y * Util.toCos(angle);
            double second = z * Util.toSin(angle);
            return first + second;
        }

        private double rotateZClockWiseY(Double angle)
        {
            double first = x * Util.toSin(angle);
            double second = z * Util.toCos(angle);
            return first + second;
        }

        private double rotateXClockWiseY(Double angle)
        {
            double first = x * Util.toCos(angle);
            double second = -z * Util.toSin(angle);
            return first + second;
        }

        private static double normalizeAngle(Double angle)
        {
            if (angle >= 360)
            {
                angle = angle % 360;
            }
            return angle;
        }

        public Double getX()
        {
            return x;
        }
  
        internal float getXFloat()
        {
            return Convert.ToSingle(x);
        }

        public void setX(Double x)
        {
            this.x = x;
        }

        public Double getY()
        {
            return y;
        }
        internal float getYFloat()
        {
            return Convert.ToSingle(y);
        }
        public void setY(Double y)
        {
            this.y = y;
        }

        public Double getZ()
        {
            return z;
        }
        internal float getZFloat()
        {
            return Convert.ToSingle(z);
        }
        public void setZ(Double z)
        {
            this.z = z;
        }

        public MyPoint3D subtraction(MyPoint3D point)
        {
            double x = getX() - point.getX();
            double y = getY() - point.getY();
            double z = getZ() - point.getZ();
            return new MyPoint3D(x, y, z);
        }
        public Vector3D subtractionAsVector3d(MyPoint3D point)
        {
            double x = getX() - point.getX();
            double y = getY() - point.getY();
            double z = getZ() - point.getZ();
            return new Vector3D(x, y, z);
        }
        public MyPoint3D sum(MyPoint3D point)
        {
            double x = getX() + point.getX();
            double y = getY() + point.getY();
            double z = getZ() + point.getZ();
            return new MyPoint3D(x, y, z);
        }

        public double getNorma() {
            return Math.Sqrt(getX() * getX() + getY() * getY() + getZ() * getZ());
        }

        public MyPoint3D lookToOrign()
        {
            return new MyPoint3D(-x - 0.01, -y - 0.01, -z - 0.01);
        }

        public double cross(MyPoint3D point)
        {
            return getX() * point.getX() + getY() * point.getY() + getZ() * point.getZ();
        }

        public MyPoint3D mult(MyPoint3D point)
        {
            return new MyPoint3D(x * point.x, y * point.y, z * point.z);
        }
        public Vector3D getUpDirectionY()
        {
            return new Vector3D(x,z,y);
        }
        
        public override String ToString() {
            return "(" + x + " , " + y + " , " + z + ")";
        }

        
    }
}
